//
//  MaakuMarkContainerView.swift
//  MaakuMarkUI
//
//  Created by nowcoder on 2025/2/18.
//

import Foundation
import UIKit
import Maaku
import SnapKit
import libcmark_gfm

public protocol CustomNodeViewProvider {
    func viewForNode(_ node: Any, bounds: CGRect) -> UIView?
}

/// 列表类型枚举
private enum ListType {
    case ordered    // 有序列表
    case unordered  // 无序列表
    case task       // 任务列表
}

public class MaakuMarkContainerView: UIView {
    
    // MARK: - Properties
    private let textView: UITextView = {
        let textView = UITextView()
        textView.isEditable = false
        textView.isSelectable = true
        textView.backgroundColor = .clear
        textView.textContainer.lineBreakMode = .byWordWrapping
        textView.textContainerInset = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8)
        textView.textContainer.lineFragmentPadding = 0
        return textView
    }()
    
    private let style: Style = MaakuStyle()
    private var customViews: [UIView] = []
    private var customViewProvider: CustomNodeViewProvider?
    
    // MARK: - Initialization
    public override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupUI()
    }
    
    // MARK: - Setup
    private func setupUI() {
        backgroundColor = .systemBackground
        layer.cornerRadius = 12
        layer.masksToBounds = true
        
        addSubview(textView)
        
        textView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
    }
    
    // MARK: - Public Methods
    
    /// 设置自定义视图提供者，用于为特定节点类型创建自定义视图
    public func setCustomViewProvider(_ provider: CustomNodeViewProvider) {
        self.customViewProvider = provider
    }
    
    /// 渲染markdown内容
    public func render(markdown: String) {
        // 清除之前的内容和自定义视图
        clearCustomViews()
        
        do {
            // 预处理 Markdown 文本
            let processedMarkdown = preprocessMarkdown(markdown)
            
            // 解析Markdown
            let document = try Document(text: processedMarkdown)
            
            // 设置富文本
            let attributedString = document.attributedText(style: style)
            
            // 处理文本样式
            let processedAttributedString = processTextStyles(attributedString)
            
            textView.attributedText = processedAttributedString
            
            // 处理需要自定义视图的节点
            if customViewProvider != nil {
                processNodesForCustomViews(document)
            } else {
                // 如果没有自定义视图提供者，使用默认的代码块处理
                // 延迟处理代码块，确保文本布局完成
                DispatchQueue.main.async {
                    self.processCodeBlocks(document)
                }
            }
            
        } catch {
            print("解析markdown出错: \(error)")
        }
    }
    
    /// 预处理 Markdown 文本
    private func preprocessMarkdown(_ markdown: String) -> String {
        // 处理斜体标记
        var processedText = markdown
        
        // 替换 *text* 为 _text_ (使用下划线标记斜体，可能更容易被识别)
        let italicPattern = "\\*([^\\*\\n]+)\\*"
        if let regex = try? NSRegularExpression(pattern: italicPattern, options: []) {
            processedText = regex.stringByReplacingMatches(in: processedText, options: [], range: NSRange(location: 0, length: processedText.count), withTemplate: "_$1_")
        }
        
        // 确保列表项之间有空行
        processedText = ensureListItemsHaveNewlines(processedText)
        
        // 标记代码块，使其更容易被识别
        processedText = markCodeBlocks(processedText)
        
        return processedText
    }
    
    /// 标记代码块，使其更容易被识别
    private func markCodeBlocks(_ text: String) -> String {
        var processedText = text
        
        // 使用更简单的正则表达式匹配代码块
        let codeBlockPattern = "```([a-zA-Z0-9]*)\\s*([\\s\\S]*?)```"
        
        if let regex = try? NSRegularExpression(pattern: codeBlockPattern, options: []) {
            let matches = regex.matches(in: text, options: [], range: NSRange(location: 0, length: text.count))
            
            print("预处理找到 \(matches.count) 个代码块")
            
            // 从后向前处理，这样替换不会影响前面的索引
            for match in matches.reversed() {
                if match.numberOfRanges >= 3 {
                    // 提取语言和代码内容
                    let languageRange = match.range(at: 1)
                    let language = languageRange.length > 0 ? 
                        (text as NSString).substring(with: languageRange) : "code"
                    
                    let codeContentRange = match.range(at: 2)
                    let codeContent = (text as NSString).substring(with: codeContentRange)
                        .trimmingCharacters(in: .whitespacesAndNewlines)
                    
                    print("预处理代码块: 语言=\(language), 内容长度=\(codeContent.count)")
                    
                    // 创建特殊标记
                    let marker = "CODEBLOCK_START:\(language)\n\(codeContent)\nCODEBLOCK_END"
                    
                    // 替换代码块为特殊标记
                    processedText = (processedText as NSString).replacingCharacters(in: match.range, with: marker)
                }
            }
        }
        
        return processedText
    }
    
    /// 确保列表项之间有空行
    private func ensureListItemsHaveNewlines(_ text: String) -> String {
        var lines = text.components(separatedBy: .newlines)
        var result: [String] = []
        var previousLineWasList = false
        
        // 定义列表项的正则表达式模式
        let orderedListPattern = "^\\s*\\d+\\.\\s+.+$"
        let unorderedListPattern = "^\\s*[-*+]\\s+.+$"
        let taskListPattern = "^\\s*[-*+]\\s+\\[[ x]\\]\\s+.+$"
        
        // 创建正则表达式
        let orderedListRegex = try? NSRegularExpression(pattern: orderedListPattern, options: [])
        let unorderedListRegex = try? NSRegularExpression(pattern: unorderedListPattern, options: [])
        let taskListRegex = try? NSRegularExpression(pattern: taskListPattern, options: [])
        
        for (index, line) in lines.enumerated() {
            // 检查当前行是否是列表项
            let isOrderedList = orderedListRegex?.firstMatch(in: line, options: [], range: NSRange(location: 0, length: line.count)) != nil
            let isUnorderedList = unorderedListRegex?.firstMatch(in: line, options: [], range: NSRange(location: 0, length: line.count)) != nil
            let isTaskList = taskListRegex?.firstMatch(in: line, options: [], range: NSRange(location: 0, length: line.count)) != nil
            
            let isListItem = isOrderedList || isUnorderedList || isTaskList
            
            // 如果当前行是列表项
            if isListItem {
                // 如果前一行不是列表项，并且不是空行，添加一个空行
                if !previousLineWasList && index > 0 && !lines[index-1].trimmingCharacters(in: .whitespaces).isEmpty {
                    result.append("")
                }
                
                // 添加当前行
                result.append(line)
                
                // 如果是最后一行，或者下一行不是列表项，添加一个空行
                if index == lines.count - 1 || !(
                    orderedListRegex?.firstMatch(in: lines[index+1], options: [], range: NSRange(location: 0, length: lines[index+1].count)) != nil ||
                    unorderedListRegex?.firstMatch(in: lines[index+1], options: [], range: NSRange(location: 0, length: lines[index+1].count)) != nil ||
                    taskListRegex?.firstMatch(in: lines[index+1], options: [], range: NSRange(location: 0, length: lines[index+1].count)) != nil
                ) {
                    result.append("")
                }
                
                previousLineWasList = true
            } else {
                // 如果当前行不是列表项，直接添加
                result.append(line)
                previousLineWasList = false
            }
        }
        
        return result.joined(separator: "\n")
    }
    
    /// 处理文本样式，包括标题格式和其他格式化文本
    private func processTextStyles(_ attributedString: NSAttributedString) -> NSAttributedString {
        let mutableAttributedString = NSMutableAttributedString(attributedString: attributedString)
        
        // 查找所有标题的范围和级别
        let headingRanges = findAllHeadingRanges(attributedString)
        
        // 确保每个标题后面都有换行符
        ensureNewlinesAfterHeadings(mutableAttributedString, headingRanges: headingRanges)
        
        // 为每个标题应用样式
        for (range, level) in headingRanges {
            // 创建段落样式
            let paragraphStyle = NSMutableParagraphStyle()
            
            // 根据标题级别设置不同的间距
            paragraphStyle.paragraphSpacing = CGFloat(24 - level * 2)  // 段落后间距
            paragraphStyle.paragraphSpacingBefore = CGFloat(24 - level * 2)  // 段落前间距
            paragraphStyle.lineBreakMode = .byWordWrapping
            paragraphStyle.alignment = .left
            
            // 应用段落样式
            mutableAttributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: range)
            
            // 移除标题中的删除线属性（如果有）
            if let strikethroughStyle = attributedString.attribute(.strikethroughStyle, at: range.location, effectiveRange: nil) as? NSNumber, 
               strikethroughStyle.intValue > 0 {
                mutableAttributedString.removeAttribute(.strikethroughStyle, range: range)
            }
        }
        
        // 确保粗体和斜体文本正确显示
        ensureProperTextFormatting(mutableAttributedString)
        
        // 处理列表样式
        processListStyles(mutableAttributedString)
        
        return mutableAttributedString
    }
    
    /// 确保粗体和斜体文本正确显示
    private func ensureProperTextFormatting(_ attributedString: NSMutableAttributedString) {
        // 首先，找出所有明确应该有删除线的文本范围
        var deliberateStrikethroughRanges: [NSRange] = []
        
        // 查找原始文本中的 ~~...~~ 模式
        let pattern = "~~[^~]+~~"
        if let regex = try? NSRegularExpression(pattern: pattern, options: []) {
            let matches = regex.matches(in: attributedString.string, options: [], range: NSRange(location: 0, length: attributedString.length))
            for match in matches {
                deliberateStrikethroughRanges.append(match.range)
            }
        }
        
        // 遍历所有属性，修复格式问题
        attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: []) { (attrs, range, stop) in
            // 检查是否有删除线属性
            if let strikethroughStyle = attrs[.strikethroughStyle] as? NSNumber,
               strikethroughStyle.intValue > 0 {
                
                // 检查是否是故意的删除线文本
                let isDeliberateStrikethrough = deliberateStrikethroughRanges.contains { NSIntersectionRange($0, range).length > 0 }
                
                // 如果不是故意的删除线，则移除删除线属性
                if !isDeliberateStrikethrough {
                    attributedString.removeAttribute(.strikethroughStyle, range: range)
                }
            }
            
            // 确保粗体和斜体属性正确设置
            if let font = attrs[.font] as? UIFont {
                let traits = font.fontDescriptor.symbolicTraits
                
                // 处理粗体
                if traits.contains(.traitBold) && !traits.contains(.traitItalic) {
                    // 纯粗体
                    let boldFont = UIFont.boldSystemFont(ofSize: font.pointSize)
                    attributedString.addAttribute(.font, value: boldFont, range: range)
                } 
                // 处理斜体
                else if traits.contains(.traitItalic) && !traits.contains(.traitBold) {
                    // 纯斜体 - 使用系统斜体字体
                    let italicFont = UIFont.italicSystemFont(ofSize: font.pointSize)
                    attributedString.addAttribute(.font, value: italicFont, range: range)
                    
                    // 确保斜体效果明显
                    // 有些情况下可能需要添加倾斜效果
                    let obliqueness: CGFloat = 0.2 // 倾斜度
                    attributedString.addAttribute(.obliqueness, value: obliqueness, range: range)
                } 
                // 处理粗斜体
                else if traits.contains(.traitBold) && traits.contains(.traitItalic) {
                    // 尝试创建粗斜体字体
                    if let descriptor = font.fontDescriptor.withSymbolicTraits([.traitBold, .traitItalic]) {
                        let boldItalicFont = UIFont(descriptor: descriptor, size: font.pointSize)
                        attributedString.addAttribute(.font, value: boldItalicFont, range: range)
                        
                        // 添加倾斜效果以确保斜体明显
                        attributedString.addAttribute(.obliqueness, value: 0.2, range: range)
                    } else {
                        // 如果无法创建粗斜体字体，使用粗体并添加倾斜效果
                        let boldFont = UIFont.boldSystemFont(ofSize: font.pointSize)
                        attributedString.addAttribute(.font, value: boldFont, range: range)
                        attributedString.addAttribute(.obliqueness, value: 0.2, range: range)
                    }
                }
            }
        }
        
        // 查找所有斜体文本（通过 * 或 _ 标记）
        // 这是一个备用方法，用于确保斜体文本被正确识别
        let italicPattern = "\\*([^\\*]+)\\*|_([^_]+)_"
        if let italicRegex = try? NSRegularExpression(pattern: italicPattern, options: []) {
            let italicMatches = italicRegex.matches(in: attributedString.string, options: [], range: NSRange(location: 0, length: attributedString.length))
            
            for match in italicMatches {
                // 获取匹配的文本范围
                let matchRange = match.range
                
                // 应用斜体样式
                if let font = attributedString.attribute(.font, at: matchRange.location, effectiveRange: nil) as? UIFont {
                    let italicFont = UIFont.italicSystemFont(ofSize: font.pointSize)
                    attributedString.addAttribute(.font, value: italicFont, range: matchRange)
                    attributedString.addAttribute(.obliqueness, value: 0.2, range: matchRange)
                }
            }
        }
    }
    
    /// 处理列表样式
    private func processListStyles(_ attributedString: NSMutableAttributedString) {
        // 获取文本
        let text = attributedString.string
        
        // 查找所有列表项
        let listItemRanges = findAllListItemRanges(text)
        
        // 应用列表样式
        for (range, level, type) in listItemRanges {
            // 创建段落样式
            let paragraphStyle = NSMutableParagraphStyle()
            
            // 设置列表项的缩进
            let indentPerLevel: CGFloat = 20.0  // 每级缩进的宽度
            let firstLineHeadIndent: CGFloat = CGFloat(level) * indentPerLevel  // 第一行缩进
            let headIndent: CGFloat = firstLineHeadIndent + 20.0  // 其他行缩进（比第一行多，形成悬挂缩进）
            
            paragraphStyle.firstLineHeadIndent = firstLineHeadIndent
            paragraphStyle.headIndent = headIndent
            paragraphStyle.paragraphSpacing = 12.0  // 段落间距
            paragraphStyle.lineSpacing = 6.0  // 行间距
            paragraphStyle.lineBreakMode = .byWordWrapping
            
            // 应用段落样式
            attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: range)
            
            // 根据列表类型添加特定样式
            switch type {
            case .ordered:
                // 有序列表项已经包含数字，不需要额外处理
                break
            case .unordered:
                // 替换原始的项目符号为更美观的符号
                replaceListBullet(attributedString, range: range)
                break
            case .task:
                // 替换任务列表的复选框
                replaceTaskCheckbox(attributedString, range: range)
                break
            }
        }
    }
    
    /// 查找所有列表项的范围、级别和类型
    private func findAllListItemRanges(_ text: String) -> [(NSRange, Int, ListType)] {
        var listItemRanges: [(NSRange, Int, ListType)] = []
        
        // 按行分割文本
        let lines = text.components(separatedBy: .newlines)
        var currentIndex = 0
        
        for line in lines {
            // 跳过空行
            if line.trimmingCharacters(in: .whitespaces).isEmpty {
                currentIndex += line.count + 1 // +1 是为了包含换行符
                continue
            }
            
            // 计算当前行的范围
            let lineRange = NSRange(location: currentIndex, length: line.count)
            
            // 检查是否是列表项
            let (isListItem, level, type) = checkIfLineIsList(line)
            
            if isListItem, let listType = type {
                listItemRanges.append((lineRange, level, listType))
            }
            
            // 更新索引，移动到下一行
            currentIndex += line.count + 1 // +1 是为了包含换行符
        }
        
        return listItemRanges
    }
    
    /// 检查一行文本是否是列表项，并返回级别和类型
    private func checkIfLineIsList(_ line: String) -> (isListItem: Bool, level: Int, type: ListType?) {
        // 去除前导空格以计算缩进级别
        let trimmedLine = line.trimmingCharacters(in: .whitespaces)
        let indentCount = line.count - trimmedLine.count
        let level = max(1, indentCount / 2) // 每两个空格算一级缩进
        
        // 检查是否是有序列表项
        if let regex = try? NSRegularExpression(pattern: "^\\s*\\d+\\.\\s+.+$", options: []),
           regex.firstMatch(in: line, options: [], range: NSRange(location: 0, length: line.count)) != nil {
            return (true, level, .ordered)
        }
        
        // 检查是否是任务列表项
        if let regex = try? NSRegularExpression(pattern: "^\\s*[-*+]\\s+\\[[ x]\\]\\s+.+$", options: []),
           regex.firstMatch(in: line, options: [], range: NSRange(location: 0, length: line.count)) != nil {
            return (true, level, .task)
        }
        
        // 检查是否是无序列表项
        if let regex = try? NSRegularExpression(pattern: "^\\s*[-*+]\\s+.+$", options: []),
           regex.firstMatch(in: line, options: [], range: NSRange(location: 0, length: line.count)) != nil {
            return (true, level, .unordered)
        }
        
        return (false, 0, nil)
    }
    
    /// 查找所有标题的范围和级别
    private func findAllHeadingRanges(_ attributedString: NSAttributedString) -> [(NSRange, Int)] {
        var headingRanges: [(NSRange, Int)] = []
        
        // 获取普通文本的字体大小作为基准
        let baselineFont = UIFont.systemFont(ofSize: UIFont.systemFontSize)
        let baselineFontSize = baselineFont.pointSize
        
        // 遍历富文本查找标题
        attributedString.enumerateAttributes(in: NSRange(location: 0, length: attributedString.length), options: []) { (attrs, range, stop) in
            if let font = attrs[.font] as? UIFont {
                // 检查是否是标题字体（通常标题字体会更大或更粗）
                if font.pointSize > baselineFontSize {
                    // 估计标题级别（1-6）
                    // 标题级别越小，字体越大
                    var level = 1
                    
                    // 根据字体大小判断标题级别
                    let sizeDifference = font.pointSize - baselineFontSize
                    
                    if sizeDifference >= 10 {
                        level = 1  // 一级标题
                    } else if sizeDifference >= 8 {
                        level = 2  // 二级标题
                    } else if sizeDifference >= 6 {
                        level = 3  // 三级标题
                    } else if sizeDifference >= 4 {
                        level = 4  // 四级标题
                    } else if sizeDifference >= 2 {
                        level = 5  // 五级标题
                    } else {
                        level = 6  // 六级标题
                    }
                    
                    // 检查是否是粗体（通常标题会是粗体）
                    if font.fontDescriptor.symbolicTraits.contains(.traitBold) {
                        // 这是一个标题
                        headingRanges.append((range, level))
                    } else if sizeDifference > 1 {
                        // 即使不是粗体，如果字体明显大于基准，也可能是标题
                        headingRanges.append((range, level))
                    }
                }
            }
        }
        
        return headingRanges
    }
    
    /// 确保每个标题后面都有换行符
    private func ensureNewlinesAfterHeadings(_ attributedString: NSMutableAttributedString, headingRanges: [(NSRange, Int)]) {
        // 从后向前处理，这样插入不会影响前面的索引
        for (range, _) in headingRanges.reversed() {
            let endLocation = range.location + range.length
            
            // 检查标题后是否已经有换行符
            if endLocation < attributedString.length {
                let nextChar = (attributedString.string as NSString).substring(with: NSRange(location: endLocation, length: 1))
                
                if nextChar != "\n" {
                    // 在标题后插入两个换行符
                    attributedString.insert(NSAttributedString(string: "\n\n"), at: endLocation)
                } else if endLocation + 1 < attributedString.length {
                    // 检查是否只有一个换行符
                    let secondChar = (attributedString.string as NSString).substring(with: NSRange(location: endLocation + 1, length: 1))
                    if secondChar != "\n" {
                        // 再插入一个换行符
                        attributedString.insert(NSAttributedString(string: "\n"), at: endLocation + 1)
                    }
                }
            }
        }
    }
    
    // MARK: - Private Methods
    
    /// 清除所有自定义视图
    private func clearCustomViews() {
        for view in customViews {
            view.removeFromSuperview()
        }
        customViews.removeAll()
        textView.textContainer.exclusionPaths = []
        pendingCodeBlocks.removeAll()
    }
    
    /// 处理需要自定义视图的内容
    private func processNodesForCustomViews(_ document: Document) {
        guard let customViewProvider = customViewProvider else {
            // 如果没有自定义视图提供者，使用默认的代码块处理
            processCodeBlocks(document)
            return
        }
        
        // 获取富文本内容
        guard let attributedText = textView.attributedText else { return }
        
        // 查找特定的标记或属性，这些可能表示需要自定义视图的位置
        // 例如，可以查找代码块、图片标记等
        
        // 示例：查找代码块（假设代码块有特定的属性）
        attributedText.enumerateAttribute(.font, in: NSRange(location: 0, length: attributedText.length), options: []) { (value, range, stop) in
            if let font = value as? UIFont, font.familyName == "Menlo" { // 假设代码块使用 Menlo 字体
                if let rect = rectForRange(range) {
                    // 创建一个代表代码块的节点（这里需要根据实际情况调整）
                    let codeText = attributedText.attributedSubstring(from: range).string
                    
                    // 尝试获取自定义视图
                    if let customView = customViewProvider.viewForNode(codeText, bounds: rect) {
                        // 添加自定义视图到文本视图
                        textView.addSubview(customView)
                        customView.frame = rect
                        customViews.append(customView)
                        
                        // 创建排除路径，使文本流绕过视图
                        let exclusionPath = UIBezierPath(rect: rect)
                        var exclusionPaths = textView.textContainer.exclusionPaths
                        exclusionPaths.append(exclusionPath)
                        textView.textContainer.exclusionPaths = exclusionPaths
                        
                        // 存储视图索引
                        customView.tag = customViews.count
                    }
                }
            }
        }
        
        // 也可以查找其他类型的节点，如图片、表格等
        // 例如，查找图片附件
        attributedText.enumerateAttribute(NSAttributedString.Key.attachment, in: NSRange(location: 0, length: attributedText.length), options: []) { (value, range, stop) in
            if let attachment = value as? NSTextAttachment, let rect = rectForRange(range) {
                if let customView = customViewProvider.viewForNode(attachment, bounds: rect) {
                    // 添加自定义视图到文本视图
                    textView.addSubview(customView)
                    customView.frame = rect
                    customViews.append(customView)
                    
                    // 创建排除路径，使文本流绕过视图
                    let exclusionPath = UIBezierPath(rect: rect)
                    var exclusionPaths = textView.textContainer.exclusionPaths
                    exclusionPaths.append(exclusionPath)
                    textView.textContainer.exclusionPaths = exclusionPaths
                    
                    // 存储视图索引
                    customView.tag = customViews.count
                }
            }
        }
    }
    
    /// 处理代码块
    private func processCodeBlocks(_ document: Document) {
        // 获取富文本内容
        guard let attributedText = textView.attributedText else { return }
        
        // 查找代码块标记
        let codeBlockPattern = "CODEBLOCK_START:([a-zA-Z0-9]*)\\n([\\s\\S]*?)\\nCODEBLOCK_END"
        
        if let regex = try? NSRegularExpression(pattern: codeBlockPattern, options: []) {
            // 查找所有代码块标记
            let matches = regex.matches(in: attributedText.string, options: [], range: NSRange(location: 0, length: attributedText.length))
            
            print("找到 \(matches.count) 个代码块")
            
            // 首先收集所有代码块信息，但不立即处理
            var codeBlocks: [(range: NSRange, language: String, content: String)] = []
            
            for match in matches {
                if match.numberOfRanges >= 3 {
                    // 提取语言和代码内容
                    let languageRange = match.range(at: 1)
                    let language = (attributedText.string as NSString).substring(with: languageRange)
                    
                    let codeContentRange = match.range(at: 2)
                    let codeContent = (attributedText.string as NSString).substring(with: codeContentRange)
                    
                    codeBlocks.append((match.range, language, codeContent))
                }
            }
            
            // 清除现有的自定义视图
            clearCustomViews()
            
            // 创建一个新的富文本，用于替换代码块
            let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText)
            
            // 从后向前处理，这样替换不会影响前面的索引
            for (index, codeBlock) in codeBlocks.enumerated().reversed() {
                // 创建代码块视图
                let codeBlockView = CodeBlockView(codeText: codeBlock.content, language: codeBlock.language)
                
                // 计算视图大小
                let viewWidth = textView.frame.width - 16 // 减去文本视图的内边距
                let viewHeight = codeBlockView.calculateHeight(forWidth: viewWidth)
                
                // 在代码块位置插入占位符
                // 使用不可见字符作为占位符，这样不会影响文本的布局
                let placeholder = NSAttributedString(string: "\u{200B}", attributes: [.foregroundColor: UIColor.clear])
                
                // 替换代码块为占位符
                mutableAttributedText.replaceCharacters(in: codeBlock.range, with: placeholder)
                
                // 存储代码块信息，用于稍后添加视图
                let codeBlockInfo = (
                    index: index,
                    range: NSRange(location: codeBlock.range.location, length: 1), // 占位符只有一个字符
                    view: codeBlockView,
                    width: viewWidth,
                    height: viewHeight
                )
                
                // 将代码块信息添加到数组
                pendingCodeBlocks.append(codeBlockInfo)
            }
            
            // 更新文本视图的内容
            textView.attributedText = mutableAttributedText
            
            // 在下一个布局周期添加代码块视图
            DispatchQueue.main.async {
                self.addCodeBlockViews()
            }
        }
    }
    
    /// 存储待处理的代码块信息
    private var pendingCodeBlocks: [(index: Int, range: NSRange, view: CodeBlockView, width: CGFloat, height: CGFloat)] = []
    
    /// 添加代码块视图
    private func addCodeBlockViews() {
        // 获取文本视图的内容
        guard let text = textView.text else { return }
        
        // 使用 textView 的布局管理器获取更准确的位置信息
        let layoutManager = textView.layoutManager
        let textContainer = textView.textContainer
        let textStorage = textView.textStorage
        
        // 计算每个代码块的位置
        for (index, codeBlock) in pendingCodeBlocks.enumerated() {
            // 获取代码块占位符的位置
            let glyphRange = layoutManager.glyphRange(forCharacterRange: codeBlock.range, actualCharacterRange: nil)
            
            // 获取占位符的边界矩形
            let boundingRect = layoutManager.boundingRect(forGlyphRange: glyphRange, in: textContainer)
            
            // 调整为视图坐标系
            let viewRect = CGRect(
                x: boundingRect.origin.x + textView.textContainerInset.left,
                y: boundingRect.origin.y + textView.textContainerInset.top,
                width: boundingRect.width,
                height: boundingRect.height
            )
            
            // 设置视图位置
            let viewFrame = CGRect(
                x: 8,
                y: viewRect.origin.y,
                width: codeBlock.width,
                height: codeBlock.height
            )
            codeBlock.view.frame = viewFrame
            
            print("添加代码块视图 \(index): \(viewFrame)")
            
            // 添加视图
            textView.addSubview(codeBlock.view)
            customViews.append(codeBlock.view)
            
            // 创建排除路径，使文本流绕过视图
            let exclusionPath = UIBezierPath(rect: viewFrame)
            var exclusionPaths = textView.textContainer.exclusionPaths
            exclusionPaths.append(exclusionPath)
            textView.textContainer.exclusionPaths = exclusionPaths
        }
        
        // 清除待处理的代码块
        pendingCodeBlocks.removeAll()
    }
    
    /// 布局完成后调整自定义视图位置
    private func adjustCustomViewsAfterLayout() {
        // 在文本布局完成后，可能需要重新调整自定义视图的位置
        // 这是因为文本布局可能会改变，特别是在添加exclusion paths后
        
        // 此处可以添加额外的调整逻辑
    }
    
    /// 计算文本范围的矩形区域
    private func rectForRange(_ range: NSRange) -> CGRect? {
        let beginning = textView.beginningOfDocument
        
        guard let start = textView.position(from: beginning, offset: range.location),
              let end = textView.position(from: start, offset: range.length),
              let textRange = textView.textRange(from: start, to: end) else {
            return nil
        }
        
        return textView.firstRect(for: textRange)
    }
    
    /// 替换列表项目符号为更美观的符号
    private func replaceListBullet(_ attributedString: NSMutableAttributedString, range: NSRange) {
        // 获取列表项文本
        let itemText = (attributedString.string as NSString).substring(with: range)
        
        // 查找项目符号的位置
        if let bulletRange = itemText.range(of: "- ") ?? itemText.range(of: "* ") ?? itemText.range(of: "+ ") {
            // 计算项目符号在原文本中的范围
            let bulletLocation = range.location + NSRange(bulletRange, in: itemText).location
            let bulletLength = 2 // "- ", "* " 或 "+ " 的长度
            
            // 创建新的项目符号
            let bulletAttrs = attributedString.attributes(at: bulletLocation, effectiveRange: nil)
            let newBullet = NSAttributedString(string: "• ", attributes: bulletAttrs)
            
            // 替换项目符号
            attributedString.replaceCharacters(in: NSRange(location: bulletLocation, length: bulletLength), with: newBullet)
        }
    }
    
    /// 替换任务列表的复选框
    private func replaceTaskCheckbox(_ attributedString: NSMutableAttributedString, range: NSRange) {
        // 获取列表项文本
        let itemText = (attributedString.string as NSString).substring(with: range)
        
        // 查找复选框的位置
        if let checkboxRange = itemText.range(of: "[ ]") {
            // 未完成任务
            let checkboxLocation = range.location + NSRange(checkboxRange, in: itemText).location
            let checkboxLength = 3 // "[ ]" 的长度
            
            // 创建新的复选框
            let checkboxAttrs = attributedString.attributes(at: checkboxLocation, effectiveRange: nil)
            let newCheckbox = NSAttributedString(string: "☐ ", attributes: checkboxAttrs)
            
            // 替换复选框
            attributedString.replaceCharacters(in: NSRange(location: checkboxLocation, length: checkboxLength), with: newCheckbox)
        } else if let checkboxRange = itemText.range(of: "[x]") {
            // 已完成任务
            let checkboxLocation = range.location + NSRange(checkboxRange, in: itemText).location
            let checkboxLength = 3 // "[x]" 的长度
            
            // 创建新的复选框
            let checkboxAttrs = attributedString.attributes(at: checkboxLocation, effectiveRange: nil)
            let newCheckbox = NSAttributedString(string: "☑ ", attributes: checkboxAttrs)
            
            // 替换复选框
            attributedString.replaceCharacters(in: NSRange(location: checkboxLocation, length: checkboxLength), with: newCheckbox)
        }
    }
}

/// 代码块信息结构体
private struct CodeBlockInfo {
    let view: CodeBlockView
    let originalRange: NSRange
    let adjustedLocation: Int
    let width: CGFloat
    let height: CGFloat
}

/// 存储代码块信息
private var codeBlockInfos: [CodeBlockInfo] = []

